#include "tcp_server.hpp"

#define default_count 5

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        cout << "格式错误\n正确格式:" << argv[0] << " ip"
             << " port" << endl;
    }
    string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    int count = 1;
    while (count <= default_count)
    {
        // 1.创建套接字
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd == -1)
        {
            lg.Log_infom(Fatal, "创建套接字失败error:%d,strerrno:%s,sockfd = %d", errno, strerror(errno), sockfd);
            exit(-1);
        }
        lg.Log_infom(Debug, "创建套接字成功,sockfd = %d", sockfd);

        // 需要绑定网络信息，但是不用显式绑定，一般在通信的时候就自动绑定上了
        // tcp在发起连接的时候就被os绑定好了

        // 2.建立连接
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;   // socket inet(ip) 协议家族,绑定网络通信的信息
        server.sin_port = htons(port); // 将主机端口号转成网络
        // server.sin_addr.s_addr = inet_addr(ip.c_str()); // 转成网络序列的四字节ip
        inet_pton(AF_INET, ip.c_str(), &server.sin_addr); // 转成网络序列的四字节ip

        int n = connect(sockfd, (sockaddr *)&server, sizeof(server)); // 自动bind

        string tmp; // 先读取任务类型
        if (n == -1)
        {
            lg.Log_infom(Fatal, "客户端连接失败...连接次数: %d", count++);
            sleep(1);
            goto END; // 该段代码段之间不能创建对象
        }

        lg.Log_infom(Error, "客户端建立连接成功,connect_ret: %d", n);
        count = 1;

        // 3.数据传输

        cout << "please enter style: ";
        getline(cin, tmp);
        write(sockfd, tmp.c_str(), tmp.size()); // 对端已经关闭，写端继续写的话就会触发异常

        while (1)
        {
            string s;
            cout << "please enter: ";
            getline(cin, s);
            int m = write(sockfd, s.c_str(), s.size()); // 对端已经关闭，写端继续写的话就会触发异常
            if (m > 0)                                  // 发送成功
            {
                char buffer[1024] = {0};
                int n = read(sockfd, buffer, sizeof(buffer) - 1);

                if (n > 0)
                {
                    buffer[n] = 0;
                    lg.Log_infom(Debug, "client recieve info:%s", buffer);
                    break;
                }
                else if (n == 0) // 读到文件末尾
                {
                    lg.Log_infom(Info, "数据已经全部读取完毕,即服务端关闭了文件描述符sockfd...");
                    break;
                }
                else
                {
                    lg.Log_infom(Error, "数据读取失败");
                    break;
                }
            }
            else
            {
                cout << "写数据失败" << endl;
                break;
            }
        }
    END:
        close(sockfd);
        
    }

    return 0;
}